package com.et114.core.utility;

import java.io.*;
import java.math.*;
import java.util.*;
public class IOUtils
{
	public static void writeByte( ObjectOutput out, byte v ) throws IOException {
		out.write( v );
	}
	
	public static void writeShort( ObjectOutput out, short v ) throws IOException {
		out.write( (v >>> 8) & 0xFF );
		out.write( (v >>> 0) & 0xFF );
	}
	
	public static void writeInt( ObjectOutput out, int v ) throws IOException {
		out.write( (v >>> 24) & 0xFF );
		out.write( (v >>> 16) & 0xFF );
		out.write( (v >>>  8) & 0xFF );
		out.write( (v >>>  0) & 0xFF );
	}
	
	public static void writeFloat( ObjectOutput out, float v ) throws IOException {
		writeInt( out, Float.floatToIntBits(v) );
	}
	
	public static void writeLong( ObjectOutput out, long v ) throws IOException {
		out.write( (int)(v >>> 56) & 0xFF );
		out.write( (int)(v >>> 48) & 0xFF );
		out.write( (int)(v >>> 40) & 0xFF );
		out.write( (int)(v >>> 32) & 0xFF );
		out.write( (int)(v >>> 24) & 0xFF );
		out.write( (int)(v >>> 16) & 0xFF );
		out.write( (int)(v >>>  8) & 0xFF );
		out.write( (int)(v >>>  0) & 0xFF );
	}
	
	public static void writeDouble( ObjectOutput out, double v ) throws IOException {
		writeLong( out, Double.doubleToLongBits(v) );
	}
		
	public static int writeUTF( ObjectOutput out, String str ) throws IOException {
		int strlen = str.length();
		int utflen = 0;
		char[] charr = new char[strlen];
		int c, count = 0;
		
		str.getChars(0, strlen, charr, 0);
		
		for (int i = 0; i < strlen; i++) {
		    c = charr[i];
		    if ((c >= 0x0001) && (c <= 0x007F)) {
				utflen++;
		    } else if (c > 0x07FF) {
				utflen += 3;
		    } else {
				utflen += 2;
		    }
		}
		
		if (utflen > 65535)
		    throw new UTFDataFormatException();
		
		byte[] bytearr = new byte[utflen+2];
		bytearr[count++] = (byte) ((utflen >>> 8) & 0xFF);
		bytearr[count++] = (byte) ((utflen >>> 0) & 0xFF);
		for (int i = 0; i < strlen; i++) {
		    c = charr[i];
		    if ((c >= 0x0001) && (c <= 0x007F)) {
				bytearr[count++] = (byte) c;
		    } else if (c > 0x07FF) {
				bytearr[count++] = (byte) (0xE0 | ((c >> 12) & 0x0F));
				bytearr[count++] = (byte) (0x80 | ((c >>  6) & 0x3F));
				bytearr[count++] = (byte) (0x80 | ((c >>  0) & 0x3F));
		    } else {
				bytearr[count++] = (byte) (0xC0 | ((c >>  6) & 0x1F));
				bytearr[count++] = (byte) (0x80 | ((c >>  0) & 0x3F));
		    }
		}
		out.write(bytearr);
		
		return utflen + 2;
    }
    
    public static void writeByteArray( ObjectOutput out, byte[] b ) throws IOException {
    	writeInt( out, b.length );
    	out.write( b );
    }
    
   	public static void writeObject( ObjectOutput out, Object o ) throws IOException {
   		if ( o == null ) {
   			out.write( -1 );
   		} else if ( o instanceof String ) {
   			out.write( 1 );
   			writeUTF( out, (String)o );
   		} else if ( o instanceof BigDecimal ) {
   			out.write( 2 );
			BigDecimal bd = (BigDecimal)o;
			writeInt( out, bd.scale() );
			writeByteArray( out, bd.unscaledValue().toByteArray() );
		} else if ( o instanceof Date ) {
			out.write( 3 );
			writeLong( out, ((Date)o).getTime() );
		} else if ( o instanceof Integer ) {
			out.write( 4 );
			writeInt( out, ((Integer)o).intValue() );
		} else if ( o instanceof Long ) {
			out.write( 5 );
			writeLong( out, ((Long)o).longValue() );
		} else if ( o instanceof Boolean ) {
			out.write( 6 );
			out.write( ((Boolean)o).booleanValue() ? 1 : 0 );
		} else if ( o instanceof BigInteger ) {
			out.write( 7 );
			writeByteArray( out, ((BigInteger)o).toByteArray() );
		} else if ( o instanceof byte[] ) {
			out.write( 8 );
			writeByteArray( out, (byte[])o );
		} else if ( o instanceof Double ) {
			out.write( 9 );
			writeDouble( out, ((Double)o).doubleValue() );
		} else if ( o instanceof Float ) {
			out.write( 10 );
			writeFloat( out, ((Float)o).floatValue() );
		} else if ( o instanceof Byte ) {
			out.write( 11 );
			out.write( ((Byte)o).byteValue() );
		} else if ( o instanceof Short ) {
			out.write( 12 );
			writeShort( out, ((Short)o).shortValue() );
		} else {
			out.write( 13 );
			out.writeObject( o );
		} 
	}
	
	public static byte readByte( ObjectInput in ) throws IOException {
		int ch = in.read();
		if (ch < 0)
		    throw new EOFException();
		return (byte)(ch);
	}
	
	public static short readShort( ObjectInput in ) throws IOException {
		int ch1 = in.read();
		int ch2 = in.read();
		if ((ch1 | ch2) < 0)
		     throw new EOFException();
		return (short)((ch1 << 8) + (ch2 << 0));
	}
	
	public static int readInt( ObjectInput in ) throws IOException {
		int ch1 = in.read();
		int ch2 = in.read();
		int ch3 = in.read();
		int ch4 = in.read();
		if ((ch1 | ch2 | ch3 | ch4) < 0)
		     throw new EOFException();
		return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0));
	}
	
	public static float readFloat( ObjectInput in ) throws IOException {
		return Float.intBitsToFloat(readInt(in));
	}
	
	public static long readLong( ObjectInput in ) throws IOException {
		return ((long)(readInt(in)) << 32) + (readInt(in) & 0xFFFFFFFFL);
	}
	
	public static double readDouble( ObjectInput in ) throws IOException {
		return Double.longBitsToDouble( readLong(in) );
	}
	
    public static int readFully( ObjectInput in, byte[] b, int off, int len ) throws IOException {
		int total = 0;
		for (;;) {
			int got = in.read(b, off + total, len - total);
		   	if (got < 0) {
				return (total == 0) ? -1 : total;
		    } else {
				total += got;
				if (total == len)
					return total;
			}
		}
    }
    
    public static int readFully( ObjectInput in , byte[] b ) throws IOException {
    	return readFully( in, b, 0, b.length );
    }

	public static String readUTF( ObjectInput in ) throws IOException {
		int utflen = readShort( in );
		StringBuffer str = new StringBuffer(utflen);
		byte bytearr [] = new byte[utflen];
		int c, char2, char3;
		int count = 0;
	
		readFully( in, bytearr, 0, utflen );
	
		while (count < utflen) {
	 		c = (int) bytearr[count] & 0xff;
	    	switch (c >> 4) {
		        case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
				    /* 0xxxxxxx*/
				    count++;
					str.append((char)c);
				    break;
		        case 12: case 13:
				    /* 110x xxxx   10xx xxxx*/
					count += 2;
					if (count > utflen)
						throw new UTFDataFormatException();
					char2 = (int) bytearr[count-1];
					if ((char2 & 0xC0) != 0x80)
						throw new UTFDataFormatException(); 
					str.append((char)(((c & 0x1F) << 6) | (char2 & 0x3F)));
					break;
		        case 14:
					/* 1110 xxxx  10xx xxxx  10xx xxxx */
					count += 3;
					if (count > utflen)
						throw new UTFDataFormatException();
					char2 = (int) bytearr[count-2];
					char3 = (int) bytearr[count-1];
					if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80))
						throw new UTFDataFormatException();	  
					str.append((char)(((c& 0x0F) << 12) |
										((char2 & 0x3F) << 6)  |
										((char3 & 0x3F) << 0)));
					break;
		        default:
					/* 10xx xxxx,  1111 xxxx */
					throw new UTFDataFormatException();		  
			}
		}
	    // The number of chars produced may be less than utflen
	    return new String(str);
	}
			
	public static byte[] readByteArray( ObjectInput in ) throws IOException {
		int len = readInt( in );
		byte[] bb = new byte[len];
		readFully( in, bb );
		return bb;
	}
		
  	public static Object readObject( ObjectInput in ) throws IOException, ClassNotFoundException {
  		int b = in.readByte();
  		switch( b ) {
  			case -1:
  				return null;
  			case 1:
  				return readUTF( in );
  			case 2:
				int scale = readInt( in );
				byte[] bb = readByteArray( in );
				return new BigDecimal( new BigInteger(bb), scale );
			case 3:
				return new Date( readLong(in) );
			case 4:
				return new Integer( readInt(in) );
			case 5:
				return new Long( readLong(in) );
			case 6:
				return (in.readByte() == 1 ) ? Boolean.TRUE: Boolean.FALSE;
			case 7:
				return new BigInteger( readByteArray(in) );
			case 8:
				return readByteArray( in );
			case 9:
				return new Double( readDouble(in) );
			case 10:
				return new Float( readFloat(in) );
			case 11:
				return new Byte( readByte(in) );
			case 12:
				return new Short( readShort(in) );
			default:
				return in.readObject();
		}	
	}
	
	public static void main(String[] args) throws Exception {
		ObjectOutputStream out1 = new ObjectOutputStream( new FileOutputStream("d:\\io1.dat") );
		out1.writeObject( "�л����񹲺͹�Ӵ˵����ˣ��й�����Ӵ�վ��4��" );
		out1.writeObject( new BigDecimal("1234567890.123456789") );
		out1.close();
		ObjectOutputStream out = new ObjectOutputStream( new FileOutputStream("d:\\io.dat") );
		writeObject( out, "�л����񹲺͹�Ӵ˵����ˣ��й�����Ӵ�վ��4��" );
		writeObject( out, new BigDecimal("1234567890.123456789") );
		out.close();
		ObjectInputStream in = new ObjectInputStream( new FileInputStream("d:\\io.dat") );
		System.out.println( readObject(in) );
		System.out.println( readObject(in) );
		in.close();
	}
}